﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;

namespace Chat.Server
{
    /// <summary>
    /// Args for event, risen by the WelcomeClient instanse, upon the
    /// new client connected to the chat server.
    /// </summary>
    public class ClientConnectedEventArgs : EventArgs
    {
        /// <summary>
        /// The communication channel between the chat server and the newly
        /// connected client.
        /// </summary>
        public Connection<ServerCmd> Connection { get; protected set; }

        public ClientConnectedEventArgs(Connection<ServerCmd> conn)
        {
            Connection = conn;
        }
    }

    /// <summary>
    /// An abstraction for a mechanizm running a background thread that listens
    /// for incomming connections from chat clients.
    /// </summary>
    public abstract class WelcomeClient
    {
        /// <summary>
        /// The thread that listens for incoming client connections.
        /// </summary>
        protected Thread ListenerThread { get; set; }

        public WelcomeClient()
        {
            ListenerThread = new Thread(WelcomeClientThreadMain);
            ListenerThread.IsBackground = true;
        }

        /// <summary>
        /// Occurs when accepted the new connection from the chat client.
        /// </summary>
        public event EventHandler<ClientConnectedEventArgs> ClientConnected;
        /// <summary>
        /// Occurs when the background listener thread exits.
        /// </summary>
        public event EventHandler Exit;
        /// <summary>
        /// Starts the listener thread.
        /// </summary>
        public void Start()
        {
            Open();

            try
            {
                ListenerThread.Start();
            }
            catch (Exception ex)
            {
                try
                {
                    Close();
                }
                catch (Exception)
                {
                }

                throw ex;
            }
        }
        /// <summary>
        /// Stops the listener thread.
        /// </summary>
        public void Stop()
        {
            if (Thread.CurrentThread.ManagedThreadId != ListenerThread.ManagedThreadId)
            {
                if (ListenerThread.IsAlive)
                    ListenerThread.Abort();

                Close();
            }
            else
            {
                throw new ApplicationException("Bad function invocation context");
            }
        }
        /// <summary>
        /// The listener thread entry point.
        /// </summary>
        protected void WelcomeClientThreadMain()
        {
            try
            {
                ProcessIncommingConnections();
            }
            catch (ThreadAbortException)
            {
            }
            catch (Exception)
            {
                Close();
                OnExit();
            }
        }
        /// <summary>
        /// Rises the ClientConnected event.
        /// </summary>
        /// <param name="e">The event argumants.</param>
        protected virtual void OnClientConnected(ClientConnectedEventArgs e)
        {
            if (ClientConnected != null)
                ClientConnected(this, e);
        }
        /// <summary>
        /// Rises the Exit event.
        /// </summary>
        protected virtual void OnExit()
        {
            if (Exit != null)
                Exit(this, EventArgs.Empty);
        }
        /// <summary>
        /// When overriden in a derived class, the method blocks awaiting for
        /// incommind client connection.
        /// </summary>
        /// <returns>The communication channel with the newly connected client.</returns>
        protected abstract Connection<ServerCmd> AcceptClient();

        /// <summary>
        /// When overriden in a derived class, creates/opens/initializes the system
        /// resources, necessary prior to start listening for incomming client
        /// connections.
        /// </summary>
        protected abstract void Open();
        /// <summary>
        /// When overriden in a derived class, releases the system resources
        /// aquired in the Open() method.
        /// </summary>
        protected abstract void Close();

        /// <summary>
        /// The listener thread endless loop, where it awaits for incomming clients.
        /// </summary>
        private void ProcessIncommingConnections()
        {
            while (true)
            {
                Connection<ServerCmd> conn = AcceptClient();

                if (conn == null)
                    continue;

                OnClientConnected(new ClientConnectedEventArgs(conn));
            }
        }

    }
}
